﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net;
namespace Flame.Socket
{
    public enum StatusServer
    {
        None, Starting, Started, WaitingForClient, ConnectedClient, Receiving, ReceivingEnd, Sending, SendingEnd, ConnectionClientClosing
    }

    public class TcpServer_
    {
        public class Message
        {
            public int Id { get; set; }
            public string Script { get; set; }
        }

        public class Result
        {
            public string Data { get; set; }
        }

        public class MessageEventArgs : EventArgs
        {
            public Message Message { get; set; }
            public Result Result { get; set; }
        }

        public StatusServer StatusServer { get; private set; }
        Thread _thread;
        const int _BufferSize = 100;
#if UNITY
#else
        System.Net.Sockets.Socket _socket;
#endif
        public event EventHandler<MessageEventArgs> OnMessage;
        public event EventHandler<MessageEventArgs> OnEnd;

        
#if UNITY
#else
        System.Net.Sockets.TcpListener _myListener = null;
#endif
        Queue<Message> _tobesend = new Queue<Message>();

        public void Start()
        {
            StatusServer = StatusServer.Starting;
            _thread.Start();
        }

        public void Send(Message message)
        {
            _tobesend.Enqueue(message);
        }

        public void Close()
        {
            StatusServer = StatusServer.ConnectionClientClosing;
            exit(null, null);
        }

        void exit(Message m, Result result)
        {
#if UNITY
#else
            if (_socket != null) _socket.Close();
            if (_myListener != null) _myListener.Stop();
            if (OnEnd != null) OnEnd(this, new MessageEventArgs() { Message = m, Result = result });
            _thread.Interrupt();
#endif
        }



        public TcpServer_(string hostName, int port, int bufferSize = _BufferSize)
        {
#if UNITY
#else
            StatusServer = StatusServer.None;
            _thread = new Thread(new ThreadStart(() =>
            {
                try
                {
                    StatusServer = StatusServer.Started;
                    _myListener = new System.Net.Sockets.TcpListener(IPAddress.Parse(hostName), port);


                    _myListener.Start();
                    System.Diagnostics.Debug.WriteLine("myListener started");

                    StatusServer = StatusServer.WaitingForClient;
                    _socket = _myListener.AcceptSocket();
                    StatusServer = StatusServer.ConnectedClient;
                    while (StatusServer != StatusServer.ConnectionClientClosing)
                    {
                        if (_tobesend.Count > 0)
                        {
                            StatusServer = StatusServer.Sending;
                            Message m = _tobesend.Dequeue();
                            try
                            {
                                _socket.Send(BitConverter.GetBytes(m.Script.Length));
                                _socket.Send(System.Text.Encoding.ASCII.GetBytes(m.Script));

                                byte[] b = new byte[bufferSize];
                                StringBuilder sb = new StringBuilder();
                                while (StatusServer != StatusServer.ConnectionClientClosing && StatusServer != StatusServer.ReceivingEnd)
                                {
                                    if(StatusServer != StatusServer.ConnectionClientClosing)
                                        StatusServer = StatusServer.Receiving;
                                    int k = _socket.Receive(b);
                                    for (int i = 0; i < k; i++)
                                    {
                                        if (b[i] == 0)
                                        {
                                            if (OnMessage != null) OnMessage(this, new MessageEventArgs() { Message = m, Result = new Result() { Data = sb.ToString() } });
#if NET35
                                            sb = new StringBuilder();
#else
                                            sb.Clear();
#endif

                                            if (StatusServer != StatusServer.ConnectionClientClosing)
                                                StatusServer = StatusServer.ReceivingEnd;
                                            break;
                                        }
                                        else
                                            sb.Append(Convert.ToChar(b[i]));
                                    }
                                }
                            }
                            catch (System.Exception e)
                            {
                                exit(m, new Result() { Data = e.Message });
                            }
                        }
                    }
                    exit(null, null);

                }
                catch (System.Exception e)
                {
                    exit(null, new Result() { Data = e.Message });
                }

            }));
#endif
        }
    }
}
